<template>
  <div class="three-wrapper">
    <div class="box" ref="box"></div>
    <div class="actions">
      <div class="info-panel" v-if="selectedRegion">
        <h3>区域信息</h3>
        <p><strong>名称:</strong> {{ selectedRegion.name }}</p>
        <p><strong>编码:</strong> {{ selectedRegion.adcode }}</p>
        <button @click="clearSelection">清除选择</button>
      </div>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3'
import axios from 'axios'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

const clock = new THREE.Clock()
const FPS = 30
const renderT = 1 / FPS
let timeS = 0

export default {
  components: {},
  props: {},
  data() {
    return {
      el: null,
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      animationFrameId: null,
      projection: null,
      raycaster: null,
      mouse: null,
      extrudeMeshes: [], // 存储所有拉伸的3D地图区域
      lineMeshes: [], // 存储所有线条
      selectedMesh: null, // 当前选中的mesh
      originalColors: new Map(), // 存储原始颜色
      selectedRegion: null, // 选中的区域信息
      extrudeOptions: {
        depth: -2,
        steps: 10,
        bevelEnabled: true,
        bevelThickness: 0,
        bevelSize: 0,
        bebelSegments: 0,
        curveSegments: 0
      }
    }
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    this.el = this.$refs['box']
    this.clock = new THREE.Clock()
    this.initThree()
  },
  beforeDestroy() {
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId)
    }
    // 移除事件监听
    this.el.removeEventListener('click', this.onClick)
  },
  methods: {
    initThree() {
      this.initScene()
      this.initCamera()
      this.initRender()
      this.initLight()
      this.initControls()
      this.initRaycaster() // 初始化光线投射
      this.animate()
      this.scene.add(this.setGridHelper(100 * 2, 10 * 2))
      this.scene.add(this.setAxesHelper(100000))

      this.drawMap()
    },

    // 初始化光线投射
    initRaycaster() {
      this.raycaster = new THREE.Raycaster()
      this.mouse = new THREE.Vector2()

      // 添加点击事件监听
      this.el.addEventListener('click', this.onClick, false)
    },

    // 点击事件处理
    onClick(event) {
      const rect = this.el.getBoundingClientRect()
      this.mouse.x = ((event.clientX - rect.left) / this.el.offsetWidth) * 2 - 1
      this.mouse.y =
        -((event.clientY - rect.top) / this.el.offsetHeight) * 2 + 1

      this.handleMapClick()
    },

    // 处理地图点击
    handleMapClick() {
      if (!this.raycaster || this.extrudeMeshes.length === 0) return

      // 更新射线
      this.raycaster.setFromCamera(this.mouse, this.camera)

      // 计算与所有拉伸mesh的交点
      const intersects = this.raycaster.intersectObjects(this.extrudeMeshes)

      if (intersects.length > 0) {
        const clickedMesh = intersects[0].object
        const regionData = clickedMesh.userData.feature

        // 如果点击的是新的区域
        if (this.selectedMesh !== clickedMesh) {
          // 恢复之前选中的mesh的颜色
          if (this.selectedMesh) {
            this.resetMeshColor(this.selectedMesh)
          }

          // 设置新的选中mesh高亮
          this.selectedMesh = clickedMesh
          this.selectMesh(this.selectedMesh)

          // 更新选中的区域信息
          this.selectedRegion = {
            name: regionData.properties.name || '未知区域',
            adcode: regionData.properties.adcode || '未知编码',
            center: regionData.properties.center || [],
            ...regionData.properties
          }

          // 触发自定义事件
          this.$emit('region-click', this.selectedRegion)

          console.log('点击区域:', this.selectedRegion)
        }
      } else {
        // 点击空白区域，清除选择
        this.clearSelection()
      }
    },

    // 选中mesh的高亮效果
    selectMesh(mesh) {
      // 保存原始颜色
      if (!this.originalColors.has(mesh)) {
        this.originalColors.set(mesh, {
          front: mesh.material[0].color.clone(),
          side: mesh.material[1].color.clone()
        })
      }

      // 设置选中颜色 - 更明显的颜色
      mesh.material[0].color.set('#FF4757') // 正面选中颜色 - 红色
      mesh.material[1].color.set('#FF6B81') // 侧面选中颜色 - 浅红色

      // 可选：添加轻微动画效果 - 向上移动一点
      mesh.position.z = 5 // 轻微上浮效果
    },

    // 恢复mesh原始颜色
    resetMeshColor(mesh) {
      const originalColors = this.originalColors.get(mesh)
      if (originalColors) {
        mesh.material[0].color.copy(originalColors.front)
        mesh.material[1].color.copy(originalColors.side)

        // 恢复位置
        mesh.position.z = 0
      }
    },

    // 清除选择
    clearSelection() {
      if (this.selectedMesh) {
        this.resetMeshColor(this.selectedMesh)
        this.selectedMesh = null
      }
      this.selectedRegion = null
      this.$emit('region-clear')
    },
    async drawMap() {
      const lineGroup = new THREE.Group()
      const exturdeGroup = new THREE.Group()
      const res = await this.getMapData()
      console.log('res', res)
      const regionCenter =
        (res.properties && res.properties.centroid) ||
        res.features[0]['properties']['center']
      this.projection = d3.geoMercator().center(regionCenter).translate([0, 0])

      res.features.slice(0).forEach(item => {
        var coordinates = item.geometry.coordinates
        coordinates.forEach(polygon => {
          if (polygon.length > 1) {
            polygon = [polygon]
          }

          polygon.forEach(p => {
            const lineObj = this.darwLine(p)
            const exturde = this.shapeToExturde(lineObj.shape, item) // 传递feature信息

            lineGroup.add(lineObj.mesh)
            exturdeGroup.add(exturde)

            // 存储到数组中用于光线投射
            this.extrudeMeshes.push(exturde)
            this.lineMeshes.push(lineObj.mesh)
          })
        })
      })

      let scaleSize = this.getModelScaleValue(lineGroup, 100)
      lineGroup.scale.set(scaleSize, scaleSize, scaleSize)
      exturdeGroup.scale.set(scaleSize, scaleSize, 1)
      this.scene.add(lineGroup)
      this.scene.add(exturdeGroup)
    },

    darwLine(pos) {
      const geo = new THREE.BufferGeometry()
      const shape = new THREE.Shape()
      const lineMaterial = new THREE.LineBasicMaterial({
        color: '#bb3'
      })
      for (let i = 0; i < pos.length; i++) {
        const [x, y] = this.projection(pos[i])
        if (i === 0) {
          shape.moveTo(x, -y)
        }
        shape.lineTo(x, -y)
      }
      const points = shape.getPoints()
      geo.setFromPoints(points)
      const mesh = new THREE.Line(geo, lineMaterial)
      return {
        shape,
        mesh
      }
    },

    shapeToExturde(shape, feature) {
      const geometry = new THREE.ExtrudeGeometry(shape, this.extrudeOptions)
      // 正面材质
      const material1 = new THREE.MeshBasicMaterial({
        color: '#3192FF',
        transparent: true
      })
      // 侧面材质
      const material2 = new THREE.MeshBasicMaterial({
        color: '#30DAFE',
        transparent: true,
        opacity: 0.8
      })
      const mesh = new THREE.Mesh(geometry, [material1, material2])

      // 为每个extrude mesh添加用户数据，包含feature信息
      mesh.userData = {
        type: 'mapRegion',
        feature: feature,
        originalZ: mesh.position.z // 保存原始Z位置
      }

      return mesh
    },

    getModelScaleValue(obj, referenceVal = 10000) {
      const size = this.getModelSize(obj)
      const { x, y, z } = size
      const maxVal = Math.max(x, y, z)
      const scaleValue = referenceVal / maxVal
      return scaleValue
    },

    getModelSize(model) {
      const box3 = new THREE.Box3()
      box3.expandByObject(model)
      const size = new THREE.Vector3()
      box3.getSize(size)
      return size
    },

    getMapData() {
      return axios.get('/aq-geojson/湖北省.json').then(res => res.data)
    },

    setGridHelper(size, divisions) {
      const gridHelper = new THREE.GridHelper(size, divisions)
      gridHelper.material.opacity = 0.8
      gridHelper.material.transparent = true
      return gridHelper
    },

    setAxesHelper(size) {
      return new THREE.AxesHelper(size)
    },

    initScene() {
      this.scene = new THREE.Scene()
    },

    initCamera() {
      const asp = this.el.offsetWidth / this.el.offsetHeight
      this.camera = new THREE.PerspectiveCamera(45, asp, 0.1, 10000000)
      this.camera.position.set(300, 300, 300)
      this.camera.lookAt(this.scene.position)
      this.scene.add(this.camera)
    },

    initRender(clearColor = '#000') {
      const width = this.el.offsetWidth
      const height = this.el.offsetHeight
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(width, height)
      this.el.append(this.renderer.domElement)
    },

    initLight() {
      const ambientLight = new THREE.AmbientLight('#fff', 0.4)
      this.scene.add(ambientLight)
      const directionalLight = new THREE.DirectionalLight('#fff', 0.8)
      directionalLight.position.set(30, 30, 30).normalize()
      this.scene.add(directionalLight)
    },

    initControls() {
      this.controls = new OrbitControls(
        this.camera,
        this.renderer.domElement,
        {}
      )
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.05
    },

    render() {
      const dt = this.clock.getDelta()
      const T = clock.getDelta()
      timeS = timeS + T
      if (timeS > renderT) {
        this.controls.update(dt)
        this.renderer.render(this.scene, this.camera)
        timeS = 0
      }
    },

    animate() {
      this.render()
      this.animationFrameId = requestAnimationFrame(this.animate)
    }
  }
}
</script>

<style scoped lang="scss">
.three-wrapper {
  height: 100%;
  position: relative;
  .box {
    height: 100%;
    width: 100%;
    background: url(./images/map-bg.png);
    background-size: cover;
    background-repeat: no-repeat;
    overflow: hidden;
    cursor: pointer;
  }
  .actions {
    position: absolute;
    top: 10px;
    right: 10px;
    display: flex;
    flex-direction: column;
    gap: 10px;

    .info-panel {
      background: rgba(255, 255, 255, 0.9);
      padding: 15px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      min-width: 200px;
      backdrop-filter: blur(10px);

      h3 {
        margin: 0 0 10px 0;
        color: #333;
        border-bottom: 1px solid #eee;
        padding-bottom: 5px;
      }

      p {
        margin: 5px 0;
        color: #666;
        font-size: 14px;

        strong {
          color: #333;
        }
      }

      button {
        width: 100%;
        padding: 8px 16px;
        border: none;
        background-color: #ff4757;
        color: #fff;
        border-radius: 4px;
        cursor: pointer;
        font-size: 14px;
        margin-top: 10px;
        transition: all 0.3s ease;

        &:hover {
          background-color: #ff6b81;
          transform: translateY(-1px);
        }
      }
    }

    button {
      padding: 8px 16px;
      border: none;
      background-color: #409eff;
      color: #fff;
      border-radius: 6px;
      cursor: pointer;
      font-size: 14px;
      transition: all 0.3s ease;

      &:hover {
        background-color: #66b1ff;
        transform: translateY(-2px);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
      }
    }
  }
}
</style>
